package com.uam.core.lk.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author 祝展
 * @version 1.0
 * @description
 * @Date 2019/11/22 12:02
 **/
public class HttpClientUtils {


    private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);

    /**
     * get请求.
     **/
    public static final String GET_METHOD = "get";

    /**
     * post请求.
     **/
    public static final String POST_METHOD = "post";

    public static final String UTF8 = "UTF-8";

    public static final String GBK = "GBK";

    /**
     * Httpclient对应CONNECTION_TIMEOUT对应的值
     */
    private static final Integer CONNECTION_TIMEOUT = 5000;

    /**
     * Httpclient对应SO_TIMEOUT对应的值
     */
    private static final Integer SO_TIMEOUT = 10000;

    /**
     * Httpclient对应CONNECTION_REQUEST_TIMEOUT对应的值
     */
    private static final Integer CONNECTION_REQUEST_TIMEOUT = 5000;

    private HttpClientUtils() {
    }


    /**
     * 获取HttpClient
     * @return  org.apache.http.impl.client.CloseableHttpClient
     * @Date  2019/11/22 13:42 祝展
     */
    private static CloseableHttpClient getHttpClient() {
        return HttpClients.custom().setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE).build();
    }

    /**
     * 普通get请求支持url后拼接参数，urlhurl?a=123&b=456
     * @param  urlWithParams
     * @param  header
     * @return  java.lang.String
     * @Date  2019/11/22 13:32 祝展
     */
    public static String requestGet(String urlWithParams, Map<String, String> header) {
        CloseableHttpClient httpclient = getHttpClient();
        HttpGet httpGet = new HttpGet(urlWithParams);
        //设置header
        setHttpGetHeader(httpGet, header);
        //配置请求的超时设置
        httpGet.setConfig(buildRequestConfig(null,null,null));

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpGet);
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                LogUtils.info(logger, "http请求响应状态错误", urlWithParams, "header params:" + JSON.toJSONString(header), "result:" + EntityUtils.toString(response.getEntity()));
            } else {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(entity, Charset.forName("UTF-8"));
                return jsonStr;
            }
        } catch (Exception e) {
            LogUtils.error(logger, e, "http请求异常", urlWithParams, "header params:" + JSON.toJSONString(header));
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * post请求，请求body参数传json字符串
     * @param  url
     * @param  bodyJson
     * @param  header
     * @return  java.lang.String
     * @Date  2019/11/22 13:35 祝展
     */
    public static String requestPost(String url, String bodyJson, Map<String, String> header) {
        CloseableHttpClient httpclient = getHttpClient();
        HttpPost httpPost = new HttpPost(url);
        //设置header
        setHttpPostHeader(httpPost, header);
        //配置请求的超时设置
        httpPost.setConfig(buildRequestConfig(null,null,null));

        StringEntity s = new StringEntity(StringUtils.isNotBlank(bodyJson) ? bodyJson : "", "UTF-8");
        httpPost.setEntity(s);

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                LogUtils.info(logger, "http请求响应状态错误 bodyJson: {0}, header params:{1}, HttpUtils_requestPost_invoked result:{2}", bodyJson, JSON.toJSONString(header), EntityUtils.toString(response.getEntity()));
            } else {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(entity, Charset.forName("UTF-8"));
                return jsonStr;
            }
        } catch (Exception e) {
            LogUtils.error(logger, e, "http请求异常 bodyJson: {0}, header params:{1}, HttpUtils_requestPost_invoked", bodyJson, JSON.toJSONString(header));
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * post请求，请求body参数传json字符串，且可设置超时时间
     * @param  url
     * @param  bodyJson
     * @param  header
     * @param  connectionTimeout
     * @param  soTimeout
     * @return  java.lang.String
     * @Date  2019/11/22 13:35 祝展
     */
    public static String requestPost(String url, String bodyJson, Map<String, String> header, int connectionTimeout, int soTimeout) {
        CloseableHttpClient httpclient = getHttpClient();
        HttpPost httpPost = new HttpPost(url);
        //配置请求的超时设置
        httpPost.setConfig(buildRequestConfig(soTimeout,connectionTimeout,null));
        //设置header
        setHttpPostHeader(httpPost, header);

        StringEntity s = new StringEntity(StringUtils.isNotBlank(bodyJson) ? bodyJson : "", "UTF-8");
        httpPost.setEntity(s);

        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                LogUtils.info(logger, "http请求响应状态错误 bodyJson: {0}, header params:{1}, HttpUtils_requestPost_invoked result:{2}", bodyJson, JSON.toJSONString(header), EntityUtils.toString(response.getEntity()));
            } else {
                HttpEntity entity = response.getEntity();
                return EntityUtils.toString(entity, Charset.forName("UTF-8"));
            }
        } catch (Exception e) {
            LogUtils.error(logger, e, "http请求异常 bodyJson: {0}, header params:{1}, HttpUtils_requestPost_invoked", bodyJson, JSON.toJSONString(header));
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * Description:  发送soap post请求<br/>
     * @param wsdlUrl            wsdl地址
     * @param xmlStr             拼接好的xml字符
     * @param header             请求头
     * @param connectionTimeout 超时时间 (毫秒)
     * @param soTimeout         socket超时时间 (毫秒)
     * @return
     */
    public static String requestWSPost(String wsdlUrl, String xmlStr, Map<String, String> header, int connectionTimeout, int soTimeout) {
        CloseableHttpClient httpclient = getHttpClient();
        HttpPost httpPost = new HttpPost(wsdlUrl);
        httpPost.addHeader("Content-Type", "text/xml;charset=UTF-8");
        //设置header
        setHttpPostHeader(httpPost, header);
        //配置请求的超时设置
        httpPost.setConfig(buildRequestConfig(soTimeout,connectionTimeout,null));

        StringEntity s = new StringEntity(StringUtils.isNotBlank(xmlStr) ? xmlStr : "", "UTF-8");
        httpPost.setEntity(s);
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                LogUtils.info(logger, "http请求响应状态错误 bodyJson: {0}, header params:{1}, HttpUtils_requestWSPost_invoked result:{2}", xmlStr, JSON.toJSONString(header), EntityUtils.toString(response.getEntity()));
            } else {
                HttpEntity entity = response.getEntity();
                return getMesage(EntityUtils.toString(entity, Charset.forName("UTF-8")));
            }
        } catch (Exception e) {
            LogUtils.error(logger, e, "http请求异常 bodyJson: {0}, header params:{1}, HttpUtils_requestWSPost_invoked", xmlStr, JSON.toJSONString(header));
        } finally {
            if (null != response) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     *  post form 形式提交
     * @param  url     url
     * @param  formBodyMap  form表单内容
     * @return  java.lang.String
     * @Date  2019/11/22 13:38 祝展
     * @throws Exception
     */
    public static String doPostForm(String url, Map<String, Object> formBodyMap) throws Exception {
        return doPostForm(url,formBodyMap,null);
    }


    /**
     *  post form 形式提交
     * @param url   请求url
     * @param formBodyMap   form body map参数
     * @param header    header map
     * @return  响应
     * @Date  2019/11/22 13:38 祝展
     * @throws Exception
     */
    public static String doPostForm(String url, Map<String, Object> formBodyMap,Map<String,String> header) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(buildRequestConfig(null,null,null));
        setHttpPostHeader(httpPost,header);
        List<NameValuePair> nvps = new ArrayList<>();

        formBodyMap.forEach((k, v) -> nvps.add(new BasicNameValuePair(k, String.valueOf(v))));

        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        CloseableHttpResponse response = getHttpClient().execute(httpPost);

        try {
            HttpEntity entity = response.getEntity();
            String content = EntityUtils.toString(entity, Charset.forName("UTF-8"));
            EntityUtils.consume(entity);
            return content;
        } finally {
            response.close();
        }
    }

    /**
     * 构造 RequestConfig
     * @return  RequestConfig
     * @Date  2019/11/22 13:39 祝展
     */
    private static RequestConfig buildRequestConfig(Integer so_timeout,
                                                    Integer connection_timeout,
                                                    Integer connection_request_timeout) {
        RequestConfig.Builder builder = RequestConfig.custom();
        if (so_timeout!=null){
            builder.setSocketTimeout(so_timeout);
        }else{
            builder.setSocketTimeout(SO_TIMEOUT);
        }
        if (connection_timeout!=null){
            builder.setConnectTimeout(connection_timeout);
        }else{
            builder.setConnectTimeout(CONNECTION_TIMEOUT);
        }
        if (connection_request_timeout!=null){
            builder.setConnectTimeout(connection_request_timeout);
        }else{
            builder.setConnectTimeout(CONNECTION_REQUEST_TIMEOUT);
        }
        return builder.build();
    }

    /**
     * 设置HttpPost Header
     * @param  httpPost
     * @param  header
     * @return  void
     * @Date  2019/11/22 13:40 祝展
     */
    private static void setHttpPostHeader(HttpPost httpPost, Map<String, String> header) {
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                httpPost.setHeader(entry.getKey(), entry.getValue());
            }
        }
        httpPost.addHeader("TraceId", MDC.get("TraceId"));
        if(!httpPost.containsHeader("Content-Type")){
            httpPost.addHeader("Content-Type", "text/html;charset=UTF-8");
        }
    }

    /**
     * Description:设置HttpGet Header
     *
     * @param httpGet
     * @param header
     * @Version1.0 2017年10月17日 下午12:11:09 by 代鹏（daipeng.456@gmail.com）创建
     */
    private static void setHttpGetHeader(HttpGet httpGet, Map<String, String> header) {
        if (header != null && !header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                httpGet.setHeader(entry.getKey(), entry.getValue());
            }
            System.out.println();
        }
        httpGet.addHeader("TraceId", MDC.get("TraceId"));
        System.out.println();
        if(!httpGet.containsHeader("Content-Type")){
            httpGet.addHeader("Content-Type", "text/html;charset=UTF-8");
        }
    }

    /**
     * 从参数map中构建NameValuePair数组.
     *
     * @param paramsMap
     * @return
     */
    private static NameValuePair[] getParamsFromMap(Map<String, String> paramsMap) {
        if (null != paramsMap && !paramsMap.isEmpty()) {
            NameValuePair[] params = new NameValuePair[paramsMap.size()];
            int pos = 0;
            Iterator<String> iter = paramsMap.keySet().iterator();
            while (iter.hasNext()) {
                String paramName = iter.next();
                String paramValue = paramsMap.get(paramName);

                params[pos++] = new BasicNameValuePair(paramName, paramValue);
            }
            return params;
        }
        return null;
    }

    /**
     * soap请求，请求结果字符替换
     * @param  soapAttachment
     * @return  java.lang.String
     * @Date  2019/11/22 13:36 祝展
     */
    private static String getMesage(String soapAttachment) {
        if (soapAttachment != null && soapAttachment.length() > 0) {
            int begin = soapAttachment.indexOf("<return>");
            begin = soapAttachment.indexOf(">", begin);
            int end = soapAttachment.indexOf("</return>");
            String str = soapAttachment.substring(begin + 1, end);
            str = str.replaceAll("&lt;", "<");
            str = str.replaceAll("&gt;", ">");
            str = str.replaceAll("&quot;", "\"");
            return str;
        } else {
            return "";
        }
    }
    /**
     * @param url:请求url
     * @param tokenId:拿到的tokenId
     * @param body 请求体
     * @return: 接口响应结果
     */
    public static String postToken(String url, String tokenId, String body) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Authorization", "Bearer " + tokenId);
        httpPost.addHeader("Content-Type", "application/json");
        httpPost.setEntity(new StringEntity(body, Consts.UTF_8));
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity = response.getEntity();
        String responseContent = EntityUtils.toString(entity, Consts.UTF_8);
        response.close();
        httpClient.close();
        return responseContent;
    }
}
